package com.blue.alipay.utils.sign;

import com.blue.alipay.enums.SignTypeEnum;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 支付宝签名类
 * <p> 注：sign值一律要做utf-8 URLencode !
 * @author chenjiusheng
 * @since 2016年8月30日 下午3:12:43
 */
public class AliSignature {
	
	/**
	 * 签名生成算法
	 * @param content
	 * @param signType
	 * @param key
	 * @return
	 */
	public static String generate(String content, String signType, String key) {
		// 生成签名
		if (SignTypeEnum.RSA.getValue().equals(signType)) {
			return RSA.sign(content, key, "UTF-8");
		} else if (SignTypeEnum.MD5.getValue().equals(signType)) {
			return MD5.sign(content, key, "UTF-8");
		}
		return "";
	}
	
	// =================================================================================================================================
	
	public static String createLinkString(SortedMap<String, String> paramMap, boolean needUrlEncode) throws UnsupportedEncodingException {
		StringBuilder linkString = new StringBuilder();
		Iterator<Map.Entry<String, String>> it = paramMap.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, String> entry = it.next();
			String key = entry.getKey();
			String value = entry.getValue();
			if (value == null || value.equals("")) {
				continue;
			}
			if (needUrlEncode) {
				linkString.append(key).append("=").append(URLEncoder.encode(value, "UTF-8"));
			} else {
				linkString.append(key).append("=").append(value);
			}
			if (it.hasNext())
				linkString.append("&");
		}
		return linkString.toString();
	}

	public static String createLinkStringWithDoubleQuote(SortedMap<String, String> paramMap) throws UnsupportedEncodingException {
		StringBuilder linkString = new StringBuilder();
		Iterator<Map.Entry<String, String>> it = paramMap.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, String> entry = it.next();
			String key = entry.getKey();
			String value = entry.getValue();
			if (value == null || value.equals("")) {
				continue;
			}
			linkString.append(key).append("=\"").append(value).append("\"");
			if (it.hasNext())
				linkString.append("&");
		}
		return linkString.toString();
	}
	
	// =================================================================================================================================
	
	/**
	 * 获取签名内容
	 * @param paramMap
	 * @return
	 */
	private static String getSignContent(SortedMap<String, String> paramMap) {
		if (paramMap == null) {
            return null;
        }
		StringBuilder content = new StringBuilder();
        Iterator<Map.Entry<String, String>> it = paramMap.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry<String, String> entry = it.next();
			String key = entry.getKey();
			String value = entry.getValue();
			if (value == null || value.equals("")) {
				continue;
			}
            content.append(key).append("=").append(value);
            if (it.hasNext()) content.append("&");
        }
		return content.toString();
	}
	
	public static String rsaSign(SortedMap<String, String> paramMap, String key) {
		String signContent = getSignContent(paramMap);
		return RSA.sign(signContent, key, "UTF-8");
	}
	
	// =================================================================================================================================
	
	/**
	 * 获取签名内容（删除sign_type、sign和daojia_info）
	 * @param paramMap
	 * @return
	 */
	public static String getSignCheckContentV1(Map<String, String> paramMap) {
        if (paramMap == null) {
            return null;
        }
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<String>(paramMap.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = paramMap.get(key);
            if (value == null || value.equals("") || value.equals("sign_type") || value.equals("sign") ) {
				continue;
			}
            content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
        }
        return content.toString();
    }

	/**
	 * 获取签名内容（删除sign和daojia_info，保留sign_type）
	 * @param paramMap
	 * @return
	 */
    private static String getSignCheckContentV2(Map<String, String> paramMap) {
        if (paramMap == null) {
            return null;
        }
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<String>(paramMap.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = paramMap.get(key);
            if (value == null || value.equals("") || value.equals("sign")) {
				continue;
			}
            content.append(i == 0 ? "" : "&").append(key).append("=").append(value);
        }
        return content.toString();
    }
	
	// =================================================================================================================================
	
	/**
	 * 验证签名
	 * @param paramMap
	 * @param signType
	 * @param sign
	 * @param key
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static boolean verify(Map<String, String> paramMap, String signType, String sign, String key) throws UnsupportedEncodingException {
		// 把所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String linkStr = getSignCheckContentV1(paramMap);
		// 验证签名
		if (SignTypeEnum.RSA.getValue().equals(signType)) {
			return RSA.verify(linkStr, sign, key, "UTF-8");
		} else if (SignTypeEnum.MD5.getValue().equals(signType)) {
			return MD5.verify(linkStr, sign, key, "UTF-8");
		}
		return false;
	}
	
	/**
	 * 验证签名 V2 (保留sign_type)
	 * @param paramMap
	 * @param signType
	 * @param sign
	 * @param key
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static boolean verifyV2(Map<String, String> paramMap, String signType, String sign, String key) throws UnsupportedEncodingException {
		// 把所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String linkStr = getSignCheckContentV2(paramMap);
		// 验证签名
		if (SignTypeEnum.RSA.getValue().equals(signType)) {
			return RSA.verify(linkStr, sign, key, "UTF-8");
		} else if (SignTypeEnum.MD5.getValue().equals(signType)) {
			return MD5.verify(linkStr, sign, key, "UTF-8");
		}
		return false;
	}
	
}
